home *** CD-ROM | disk | FTP | other *** search
/ Skunkware 5 / Skunkware 5.iso / src / Games / ms-0.07 / xms / Mama.c < prev    next >
Encoding:
C/C++ Source or Header  |  1995-06-27  |  20.5 KB  |  784 lines

  1. /* Mama.c - MandelSpawn master widget */
  2.  
  3. /*
  4.     This file is part of MandelSpawn, a network Mandelbrot program.
  5.  
  6.     Copyright (C) 1990-1993 Andreas Gustafsson
  7.  
  8.     MandelSpawn is free software; you can redistribute it and/or modify
  9.     it under the terms of the GNU General Public License, version 1,
  10.     as published by the Free Software Foundation.
  11.  
  12.     MandelSpawn is distributed in the hope that it will be useful,
  13.     but WITHOUT ANY WARRANTY; without even the implied warranty of
  14.     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  15.     GNU General Public License for more details.
  16.  
  17.     You should have received a copy of the GNU General Public License,
  18.     version 1, along with this program; if not, write to the Free 
  19.     Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  20. */
  21.  
  22. /*
  23.   The Mama widget is never realized.  Its purpose is to manage 
  24.   resources common to all the Ms windows, such as the colormap and 
  25.   the computation servers.  Now that the computation server interface 
  26.   has been split off into a separate module, Mama has much less to do 
  27.   than before. 
  28. */
  29.  
  30. /* On some systems, <fcntl.h> may need to be included also */
  31. #include <stdio.h>
  32. #include <errno.h>
  33. extern int errno; /* at least Sony's errno.h misses this */
  34. #include <math.h>
  35.  
  36. #include <X11/IntrinsicP.h>
  37. #include <X11/Xos.h>
  38. #include <X11/StringDefs.h>
  39. #include <X11/Shell.h>
  40.  
  41. #include "backward.h" /* X11R2 backward compatibility stuff */
  42.  
  43. #include "color.h"
  44.  
  45. #include "MamaP.h"
  46. #include "Ms.h" /* public header of the child widget */
  47.  
  48. #include "io.h"
  49. #include "work.h"
  50.  
  51. /* default timeout in milliseconds per iteration, and constant factor */
  52. #define TIMEOUT_PER_ITER     40    /* this makes 10 s for 250 iters */
  53. #define TIMEOUT_CONST        3000    /* add 3 seconds for network delays */
  54.  
  55.  
  56. /*
  57.   On the Mach/i386 machines I have tested, floor(0.26) returns -0.5.  Not 
  58.   good.  Here is a nonportable workaround that's good enough for our 
  59.   purposes. 
  60. */
  61. #ifdef BROKEN_FLOOR
  62. #define floor(x) ((double)(long)(x))
  63. #endif
  64.  
  65. extern XtAppContext thisApp;
  66. extern Display *myDisplay;
  67. extern int myScreenNo;
  68. extern Screen *myScreen;
  69.  
  70. static void Initialize(), Destroy();
  71.  
  72. static Boolean SetValues();
  73.  
  74. /* Defaults */
  75.  
  76. /* the width/height defaults are never really used */
  77. static Dimension default_width = 400;
  78. static Dimension default_height = 250;
  79. static int default_colors = 250;
  80. static int default_hues = 250;
  81. static char default_spectrum[] = 
  82.  "blue-aquamarine-cyan-medium sea green-forest green-lime green-\
  83. yellow green-yellow-coral-pink-black";
  84. static Bool default_bw = False;
  85. static Bool default_wrap = False;
  86. static Bool default_animate = False;
  87. static int default_animation_speed = 10;
  88.  
  89.  
  90. static XtResource resources[] = 
  91. {
  92.   /* Core resources */
  93.   { XtNwidth, XtCWidth, XtRDimension, sizeof(Dimension),
  94.       XtOffset(Widget, core.width), XtRDimension, 
  95.       (caddr_t) &default_width },
  96.   { XtNheight, XtCHeight, XtRDimension, sizeof(Dimension),
  97.       XtOffset(Widget, core.height), XtRDimension, 
  98.       (caddr_t) &default_height },
  99.   /* Noncore resources */
  100.   { XtNSpectrum, XtCString, XtRString, sizeof(String),
  101.       XtOffset(MamaWidget, mama.spectrum), XtRString,
  102.       default_spectrum },
  103.   { XtNColours, XtCValue, XtRInt, sizeof(int),
  104.       XtOffset(MamaWidget, mama.n_colours), XtRInt,
  105.       (caddr_t) &default_colors },
  106.   { XtNHues, XtCValue, XtRInt, sizeof(int),
  107.       XtOffset(MamaWidget, mama.n_hues), XtRInt,
  108.       (caddr_t) &default_hues },
  109.   { XtNBw, XtCValue, XtRBool, sizeof(Bool),
  110.       XtOffset(MamaWidget, mama.bw), XtRBool,
  111.       (caddr_t) &default_bw },
  112.   { XtNWrap, XtCValue, XtRBool, sizeof(Bool),
  113.       XtOffset(MamaWidget, mama.wrap), XtRBool,
  114.       (caddr_t) &default_wrap },
  115.   { XtNAnimate, XtCValue, XtRBool, sizeof(Bool),
  116.       XtOffset(MamaWidget, mama.animation.on), XtRBool,
  117.       (caddr_t) &default_animate },
  118.   { XtNAnimationSpeed, XtCValue, XtRInt, sizeof(int),
  119.       XtOffset(MamaWidget, mama.animation.speed), XtRInt,
  120.       (caddr_t) &default_animation_speed }
  121. };
  122.  
  123.  
  124. MamaClassRec mamaClassRec = 
  125. {   /* core fields */
  126.     { 
  127.     /* superclass        */    &widgetClassRec,
  128.     /* class_name        */    "Mama",
  129.     /* widget_size        */    sizeof(MamaRec),
  130.     /* class_initialize        */      NULL,
  131.     /* class_part_initialize    */    NULL,
  132.     /* class_inited        */    FALSE,
  133.     /* initialize        */    Initialize,
  134.     /* initialize_hook        */    NULL,
  135.     /* realize            */    NULL,
  136.     /* actions            */    NULL,
  137.     /* num_actions        */    0,
  138.     /* resources        */    resources,
  139.     /* resource_count        */    XtNumber(resources),
  140.     /* xrm_class        */    NULL,
  141.     /* compress_motion        */    TRUE,
  142.     /* compress_exposure    */    TRUE,
  143.     /* compress_enterleave    */    TRUE,
  144.     /* visible_interest        */    FALSE,
  145.     /* destroy            */    Destroy,
  146.     /* resize            */    NULL,
  147.     /* expose            */    NULL,
  148.     /* set_values        */    SetValues,
  149.     /* set_values_hook        */    NULL,
  150.     /* set_values_almost    */    XtInheritSetValuesAlmost,
  151.     /* get_values_hook        */    NULL,
  152.     /* accept_focus        */    NULL,
  153.     /* version            */    XtVersion,
  154.     /* callback_private        */    NULL,
  155.     /* tm_table            */    NULL,
  156.     /* query_geometry        */    NULL
  157.     },
  158.     /* noncore fields */
  159.     {
  160.     /* dummy            */    0
  161.     }
  162. };
  163.  
  164. WidgetClass mamaWidgetClass = (WidgetClass) &mamaClassRec;
  165.  
  166.  
  167. /*
  168.   Find or create a colormap for use with a PseudoColor visual
  169.   and allocate the color cells we need.  May use the default
  170.   colormap if appropriate.
  171. */
  172.   
  173. Colormap get_pseudocolor_colormap(visual, ncolours, pixels, black_ret, white_ret)
  174.   Visual *visual;        /* visual this colorormap is for */
  175.   unsigned int ncolours;    /* number of colormap entries needed */
  176.   unsigned long *pixels;    /* pixel value array return */
  177.   unsigned long *black_ret;    /* black pixel value */
  178.   unsigned long *white_ret;    /* white pixel value */
  179. { Colormap cmap;
  180.   XColor dummy;
  181.   XColor bwcells[2];
  182.   unsigned long pixval;
  183.   int i;
  184.  
  185.   /* pixel values reserved for white and black, or -1 if not used */
  186.   unsigned long white_pixel = -1, black_pixel = -1;
  187.  
  188.   if(visual == DefaultVisualOfScreen(myScreen))
  189.   {
  190.     /* Try to use the default colormap */
  191.     
  192.     XColor black, white, dummy;
  193.     cmap = DefaultColormapOfScreen(myScreen);
  194.  
  195.     /*
  196.       Try to allocate read-only cells for black and white,
  197.       and read-write cells for the color pixels we need
  198.     */
  199.     if(
  200.        XAllocNamedColor(myDisplay, cmap,
  201.             "black", &black, &dummy) &&
  202.        XAllocNamedColor(myDisplay, cmap,
  203.             "white", &white, &dummy) &&
  204.        XAllocColorCells(myDisplay, cmap,
  205.             False, NULL, 0,  
  206.             pixels, ncolours)
  207.       )
  208.     {
  209.       /* OK */    
  210.       *black_ret = black.pixel;
  211.       *white_ret = white.pixel;
  212.       return cmap; 
  213.     }
  214.     /* Fallthrough if allocation out of the default colormap failed */
  215.   }
  216.   
  217.   /* Try to allocate a colormap  of our own */
  218.   cmap = XCreateColormap(myDisplay,
  219.              DefaultRootWindow(myDisplay),
  220.              visual, AllocAll);
  221.   if(! cmap)
  222.       XtAppError(thisApp, "XCreateColormap failed");
  223.  
  224.   /*
  225.     Because the overflow label also use this colormap, 
  226.     there had better exist a white and a black pixel somewhere
  227.     in it.  Furthermore, on systems with only one hardware
  228.     colormap, the popup menu (which uses the default colormap)
  229.     may have to be displayed using this colormap.  To increase
  230.     the chances of the popup menu being readable in this case,
  231.     the white and black pixels of the default colormap should
  232.     also exist in the same locations in this colormap.
  233.   */
  234.  
  235.   if(visual->map_entries == DefaultVisualOfScreen(myScreen)->map_entries &&
  236.      XAllocNamedColor(myDisplay, DefaultColormapOfScreen(myScreen), "white",
  237.           &bwcells[0], &dummy) &&
  238.      XAllocNamedColor(myDisplay, DefaultColormapOfScreen(myScreen), "black",
  239.           &bwcells[1], &dummy))
  240.   {
  241.     bwcells[0].flags = DoRed|DoGreen|DoBlue;
  242.     bwcells[1].flags = DoRed|DoGreen|DoBlue;
  243.     XStoreColors(myDisplay, cmap, bwcells, 2);
  244.     white_pixel = bwcells[0].pixel;
  245.     black_pixel = bwcells[1].pixel;
  246.   }
  247.  
  248.   pixval=0;
  249.   for(i=0; i<ncolours; i++)
  250.   {
  251.     while(pixval == white_pixel || pixval == black_pixel)
  252.       pixval++;
  253.     pixels[i] = pixval;
  254.     pixval++;
  255.   }
  256.  
  257.   if(pixval > visual->map_entries)
  258.   { XtAppError(thisApp,
  259.   "too many colours for this screen.  Please specify a smaller number\n\
  260. of colours with the -colours option, or use -bw to run in black and\n\
  261. white.");
  262.   }
  263.  
  264.   *black_ret = black_pixel;
  265.   *white_ret = white_pixel;
  266.   return(cmap);
  267. }
  268.  
  269. cmap_error(msg)
  270.   char *msg;
  271. {
  272.   XtAppError(thisApp, msg);
  273. }
  274.  
  275. int name_to_color(name, color)
  276.   char *name;
  277.   color_t *color;
  278. {
  279.   XColor xcolor, dummy;
  280.   if(! XLookupColor(myDisplay, DefaultColormapOfScreen(myScreen), name,
  281.             &xcolor, &dummy))
  282.     return 0;
  283.   color->comps[RED_COMP] = (double) xcolor.red / 0xFFFF;
  284.   color->comps[GREEN_COMP] = (double) xcolor.green / 0xFFFF;
  285.   color->comps[BLUE_COMP] = (double) xcolor.blue / 0xFFFF;
  286.   return 1;
  287. }
  288.  
  289.  
  290. /* Set up the colormap */
  291.  
  292. static void MsColourSetup(w, mode)
  293.   MamaWidget w;
  294.   int mode;    /* PseudoColor or TrueColor */
  295. { unsigned int i;
  296.   unsigned int ncolours;
  297.   unsigned int nhues;
  298.   unsigned int nstops;
  299.   unsigned long *phpixels;
  300.   unsigned long *pixels;
  301.   color_t *physcolors;
  302.   XColor *colourset;
  303.   unsigned stops_allocated = 4; /* initial allocation of colour stops */
  304.   char *p;
  305.  
  306.   ncolours = w->mama.n_colours;
  307.   nhues = w->mama.n_hues;
  308.  
  309.   /* parse the "spectrum" resource */
  310.  
  311.   physcolors = (color_t *) XtMalloc(ncolours * sizeof(color_t));
  312.   parse_spectrum(w->mama.spectrum, ncolours, physcolors);
  313.  
  314.   /*
  315.     Physical pixel mapping (from colour number to pixel value, 
  316.     "ncolours" entries); these are simply the pixels that 
  317.     XAllocColorCells gives us 
  318.   */
  319.   phpixels =
  320.     (unsigned long *) XtMalloc(ncolours * sizeof(unsigned long));
  321.   
  322.   /*
  323.     Logical pixel mapping (from iteration count to pixel value,
  324.    "nhues" entries)
  325.   */
  326.   pixels =
  327.     (unsigned long *) XtMalloc(nhues * sizeof(unsigned long));
  328.  
  329.   /* Allocate an array representing the RGB-to-pixel mapping */
  330.   colourset = (XColor *) XtMalloc(ncolours * sizeof(XColor));
  331.  
  332.   /* Find or create a suitable X colormap */
  333.   
  334.   switch(mode)
  335.   { case PseudoColor:
  336.       /* Allocate a writeable colormap */
  337.       w->mama.my_colormap =
  338.       get_pseudocolor_colormap(w->mama.visual_info.visual,
  339.         ncolours, phpixels, &w->mama.black, &w->mama.white);
  340.       for(i=0; i<ncolours; i++)
  341.     colourset[i].pixel = phpixels[i];
  342.       break;
  343.     case TrueColor:
  344.       w->mama.my_colormap =
  345.     XCreateColormap(myDisplay, RootWindowOfScreen(myScreen),
  346.             w->mama.visual_info.visual, AllocNone);
  347.       /*
  348.     Allocate read-only white and black pixels for the
  349.     overflow label
  350.       */
  351.       { XColor black, white, dummy;
  352.  
  353.     (void) XAllocNamedColor(myDisplay, w->mama.my_colormap,
  354.                 "black", &black, &dummy);
  355.     (void) XAllocNamedColor(myDisplay, w->mama.my_colormap,
  356.                 "white", &white, &dummy);
  357.     w->mama.black = black.pixel;
  358.     w->mama.white = white.pixel;
  359.       }
  360.   }
  361.  
  362.   
  363.   for(i=0; i<ncolours; i++)
  364.   { 
  365.     colourset[i].red = (int) (0xFFFF * physcolors[i].comps[RED_COMP]+0.5);
  366.     colourset[i].green = (int) (0xFFFF * physcolors[i].comps[GREEN_COMP]+0.5);
  367.     colourset[i].blue = (int) (0xFFFF * physcolors[i].comps[BLUE_COMP]+0.5);
  368.     colourset[i].flags = DoRed|DoGreen|DoBlue;
  369.     
  370.     if(mode == TrueColor)
  371.     {
  372.       /*
  373.     Allocate a read-only colour (this is very slow -
  374.     one server round-trip per pixel!)
  375.       */
  376.       XAllocColor(myDisplay, w->mama.my_colormap, &colourset[i]);
  377.       phpixels[i] = colourset[i].pixel;
  378.     }
  379.   }
  380.   
  381.   if(w->mama.wrap)
  382.   { /*
  383.       Wrap the spectrum around several times if needed to get the 
  384.       desired number of "hues" from a limited number of "colours"
  385.     */
  386.     for(i=0; i<nhues-1; i++)
  387.     { pixels[i] = phpixels[i % ncolours];
  388.     }
  389.   }
  390.   else
  391.   { /*
  392.       Don't wrap; give the same colour to several consecutive iteration
  393.       values
  394.     */
  395.     int divfactor = (nhues + ncolours-1) / ncolours;
  396.     for(i=0; i<nhues-1; i++)
  397.     { pixels[i] = phpixels[i / divfactor];
  398.     }
  399.   }
  400.   /* ...but make sure the last colour is what the user specified. */
  401.   pixels[nhues-1] = phpixels[ncolours-1];
  402.   w->mama.pixels = pixels;
  403.   
  404.   if(mode == PseudoColor)
  405.     XStoreColors(myDisplay, w->mama.my_colormap, 
  406.          colourset, ncolours);
  407.  
  408.   /* save a shadow of the colormap for colormap animation */
  409.   w->mama.colourset = colourset;
  410.  
  411.   XtFree((char *) physcolors);
  412.   XtFree((char *) phpixels);
  413. }
  414.  
  415.  
  416. /* Various colormap animation stuff */
  417.  
  418. static void
  419. AnimationStep(w)
  420.      MamaWidget w;
  421. { int ncolours=w->mama.n_colours;
  422.   XColor *colourset = w->mama.colourset;
  423.   unsigned long tmp;
  424.   int i;
  425.   tmp = colourset[ncolours-1].pixel;
  426.   for(i=ncolours-2; i>=0; i--)
  427.     colourset[i+1].pixel = colourset[i].pixel;
  428.   colourset[0].pixel = tmp;
  429.   XStoreColors(myDisplay, w->mama.my_colormap, 
  430.            colourset, ncolours);
  431.   XSync(myDisplay, False);
  432. }  
  433.  
  434. void AddAnimationTimeout();
  435.  
  436. static void 
  437. AnimationTimeoutCallback(client_data, id) 
  438.      caddr_t client_data;
  439.      XtIntervalId *id;
  440. { MamaWidget w = (MamaWidget) client_data;
  441.   AnimationStep(w);
  442.   if(++w->mama.animation.phase == w->mama.n_colours)
  443.     w->mama.animation.phase = 0;
  444.   
  445.   if(w->mama.animation.on == ANIM_STOPPING)
  446.     w->mama.animation.on = ANIM_OFF;
  447.   else
  448.     AddAnimationTimeout(w);
  449. }
  450.  
  451. void 
  452. AddAnimationTimeout(w)
  453.      MamaWidget w;
  454. { int speed = w->mama.animation.speed;
  455.   if(speed==0)
  456.     speed=1; /* to avoid division by zero */
  457.   w->mama.animation.timeout_id =
  458.     XtAppAddTimeOut(thisApp, 1000/speed,
  459.             (XtTimerCallbackProc) AnimationTimeoutCallback,
  460.             (caddr_t) w);
  461. }
  462.  
  463. void 
  464. RemoveAnimationTimeout(w)
  465.      MamaWidget w;
  466. { XtRemoveTimeOut(w->mama.animation.timeout_id);
  467. }
  468.  
  469.  
  470. void
  471. AnimationToggle(w)
  472.      MamaWidget w;
  473. { switch(w->mama.animation.on)
  474.   { case ANIM_OFF:
  475.       AddAnimationTimeout(w);
  476.       w->mama.animation.on = ANIM_ON;
  477.       break;
  478.     case ANIM_ON:
  479.     case ANIM_STOPPING:
  480.       w->mama.animation.on = ANIM_STOPPING;
  481.       break;
  482.   }
  483. }
  484.  
  485.  
  486. /* Set up for black-and-white operation */
  487.  
  488. static void 
  489. MsBwSetup(w)
  490.      MamaWidget w;
  491. { unsigned long *pixels;
  492.  
  493.   unsigned niter=w->mama.n_hues;
  494.   register int i;
  495.   
  496.   pixels=w->mama.pixels=
  497.     (unsigned long *) XtMalloc(niter * sizeof(unsigned long));
  498.  
  499.   /* Use alternating black/white bands */
  500.   for(i=0; i<niter; i++)
  501.   { pixels[i] = (niter - i) & 0x01 ?
  502.       BlackPixelOfScreen(myScreen) : WhitePixelOfScreen(myScreen);
  503.   }
  504.   w->mama.my_colormap = DefaultColormapOfScreen(myScreen);
  505. }
  506.  
  507.  
  508. /* Initialize the widget */
  509.  
  510. static void
  511. Initialize(request, new)
  512.      MamaWidget request;
  513.      MamaWidget new;
  514. { int planes;
  515.  
  516.   /* we haven't made any popups yet */
  517.   new->mama.n_popups_created=0;
  518.  
  519.     
  520.   /* initialize the workforce */
  521.   new->mama.workforce =
  522.     wf_init(new->mama.n_hues * TIMEOUT_PER_ITER + TIMEOUT_CONST,
  523.         IO_MUX_XT, IO_MUX_XT);
  524.  
  525.  
  526.   /* initialize the Xt-based I/O multiplexing mechanism */
  527.   xio_init(wf_get_io(new->mama.workforce));
  528.     
  529. #ifndef R4
  530.   /* If you get "operation would block" errors, remove the #ifdef and */
  531.   /* #ifndef around this code, and send me (gson@niksula.hut.fi) */
  532.   /* a bug report mentioning your Xt library vendor and version. */
  533.   /* Does anyone have a clue why lots of people used to get these errors */
  534.   /* with X11R3? */
  535.  
  536.   io_ignore_ewouldblock(wf_get_io(new->mama.workforce));
  537. #endif
  538.  
  539.   if(new->mama.n_colours > new->mama.n_hues)
  540.   { /* we have more colours than iterations, throw some away */
  541.     new->mama.n_colours = new->mama.n_hues;
  542.   }
  543.  
  544.   if(new->mama.bw)
  545.     goto force_bw;
  546.  
  547.   /* look for a suitable visual type */
  548.  
  549.   /* first, look for 24-bit TrueColor visuals */
  550.   if(XMatchVisualInfo(myDisplay, myScreenNo, 24, TrueColor,
  551.               &new->mama.visual_info))
  552.   { /* Wow, a 24-bit display.  Let's use it. */
  553.     MsColourSetup(new, TrueColor);
  554.     return;
  555.   }
  556.  
  557.   /* next, look for PseudoColor visuals of 8, 4, or 2 bits */
  558.   for(planes=8; planes>=2; planes>>=1)
  559.     if(XMatchVisualInfo(myDisplay, myScreenNo, planes, PseudoColor,
  560.             &new->mama.visual_info))
  561.     { /* found a suitable PseudoColor visual; set up for flashy */
  562.       /* colour pictures */
  563.       if(new->mama.n_colours > (1<<planes))
  564.       {    char msg[256];
  565.     /* leave a few colours for window borders, etc. */
  566.     int use_colours = (1<<planes) - 4;
  567.     sprintf(msg, "%d colours is too much for a %d-plane visual,\n\
  568.   trying %d colours...\n",
  569.         new->mama.n_colours, planes, use_colours);
  570.     XtAppWarning(thisApp, msg);
  571.     new->mama.n_colours = use_colours;
  572.       }
  573.       MsColourSetup(new, PseudoColor);
  574.       return;
  575.     }
  576.  
  577.  force_bw:
  578.   /* no suitable TrueColor or PseudoColor visual found, try B/W. */
  579.   /* We simply assume that the default visual can do B/W. */
  580.   { XVisualInfo template, *ret;
  581.     int nitems;
  582.     template.visualid = XVisualIDFromVisual(DefaultVisualOfScreen(myScreen));
  583.     ret = XGetVisualInfo(myDisplay, VisualIDMask, &template, &nitems);
  584.     if(nitems != 1)
  585.       XtAppError(thisApp, "How many default visuals are there, exactly?");
  586.     new->mama.visual_info = ret[0];
  587.     MsBwSetup(new);
  588.     return;
  589.   }
  590. }
  591.  
  592.  
  593. /*
  594.   Provide error handling services to the workforce and
  595.   I/O modules
  596. */
  597.  
  598. void wf_error(msg) char *msg; { XtAppError(thisApp, msg); }
  599. void wf_warn(msg) char *msg; { XtAppWarning(thisApp, msg); }
  600.  
  601. void io_error(msg) char *msg; { XtAppError(thisApp, msg); }
  602. void io_warn(msg) char *msg; { XtAppWarning(thisApp, msg); }
  603.  
  604.  
  605. /* Update widget resources (no changeable resources so far) */
  606.  
  607. static Boolean SetValues(current, request, new)
  608.      MamaWidget current, request, new;
  609. { return(False);
  610. }
  611.  
  612.  
  613. /* Die */
  614.  
  615. void Shutdown(w)
  616.      MamaWidget w;
  617. { XCloseDisplay(XtDisplay(w));
  618.   exit(0);
  619. }
  620.  
  621.  
  622. /* This callback is called whenever a popup child dies */
  623.  
  624. static void
  625. PostMortem(w, client_data, call_data)
  626.      MsWidget w;
  627.      caddr_t client_data;
  628.      caddr_t call_data;
  629. { MamaWidget ma = (MamaWidget) client_data;
  630.   /* If our last child is dying we have nothing to live for; */
  631.   /* commit suicide */
  632.   if(ma->core.num_popups == 1)
  633.     Shutdown(ma);
  634. }
  635.  
  636.  
  637. /*
  638.   Pop up a new Ms window, making it a child of the Mama. 
  639.   The caller must make sure there is room in the "shell_args" array 
  640.   for one more arg.
  641. */
  642.  
  643. void PopupAnother (w, shell_args, num_shell_args, args, num_args)
  644.      MamaWidget w;
  645.      ArgList shell_args;
  646.      Cardinal num_shell_args;
  647.      ArgList args;
  648.      Cardinal num_args;
  649. { Widget the_widget;
  650.   Widget the_shell;
  651.   char popup_name[32]; /* unique name for each popup widget */
  652.  
  653.   sprintf(popup_name, "ms_%d", ++w->mama.n_popups_created);
  654.  
  655.   /* make the popup use our colormap */
  656.   XtSetArg(shell_args[num_shell_args], XtNcolormap, w->mama.my_colormap);
  657.   num_shell_args++;
  658.  
  659.   /* XtCreateWindow() needs _both_ a visual and a depth.  Stupid. */
  660.   XtSetArg(shell_args[num_shell_args], XtNdepth, w->mama.visual_info.depth);
  661.   num_shell_args++;
  662.   XtSetArg(shell_args[num_shell_args], XtNvisual, w->mama.visual_info.visual);
  663.   num_shell_args++;
  664.   
  665.   /* this is needed for OpenWindows... */
  666.   XtSetArg(shell_args[num_shell_args], XtNinput, True);
  667.   num_shell_args++;
  668.  
  669.   the_shell =
  670.     XtCreatePopupShell(popup_name, topLevelShellWidgetClass, (Widget) w, 
  671.                shell_args, num_shell_args);
  672.  
  673.   XtSetArg(args[num_args], XtNcolormap, w->mama.my_colormap);
  674.   num_args++;
  675.   XtSetArg(args[num_args], XtNdepth, w->mama.visual_info.depth);
  676.   num_args++;
  677.   XtSetArg(args[num_args], XtNvisual, w->mama.visual_info.visual);
  678.   num_args++;
  679.  
  680.   /*
  681.     We can't just inherit the fg and bg pixel values either because 
  682.     they might refer to the wrong visual 
  683.   */
  684.   XtSetArg(args[num_args], XtNbackground, w->mama.white);
  685.   num_args++;
  686.   XtSetArg(args[num_args], XtNforeground, w->mama.black);
  687.   num_args++;
  688.  
  689.   the_widget = XtCreateManagedWidget("view",
  690.                    (WidgetClass) msWidgetClass,
  691.                    (Widget) the_shell, 
  692.                    args, num_args);
  693.   XtAddCallback(the_widget, XtNdestroyCallback,
  694.         (XtCallbackProc) PostMortem, (caddr_t) w);
  695.         
  696.   XtPopup(the_shell, XtGrabNone);
  697. }
  698.  
  699.  
  700. /* Destroy the widget */
  701.  
  702. static void
  703. Destroy (w)
  704.   MamaWidget w;
  705. {
  706. }
  707.  
  708.  
  709. /*
  710.   The Ms widget needs to know the maximums message size,
  711.   how may colours there are, etc.  Make that information
  712.   available through public functions. 
  713. */
  714.  
  715. unsigned 
  716. MaxIterations(w)
  717.      MamaWidget w;
  718. { return(w->mama.n_hues);
  719. }
  720.  
  721. unsigned MamaHeight(w)
  722.      MamaWidget w;
  723. { return(w->core.height);
  724. }
  725.  
  726. unsigned MamaWidth(w)
  727.      MamaWidget w;
  728. { return(w->core.width);
  729. }
  730.  
  731. Colormap
  732. MamaColormap(w)
  733.      MamaWidget w;
  734. { return(w->mama.my_colormap);
  735. }
  736.  
  737. XColor *
  738. MamaColourset(w)
  739.      MamaWidget w;
  740. { return(w->mama.colourset);
  741. }
  742.  
  743. wf_state *MamaWorkforce(w)
  744.      MamaWidget w;
  745. { return(w->mama.workforce);
  746. }
  747.  
  748. XVisualInfo *MamaVisualInfo(w)
  749.      MamaWidget w;
  750. { return(&w->mama.visual_info);
  751. }
  752.  
  753. unsigned long *
  754. MamaPixels(w)
  755.      MamaWidget w;
  756. { return(w->mama.pixels);
  757. }
  758.  
  759. /*
  760.   Get the pixel values for the white and black pixels of
  761.   our colormap.  These are needed by the label widget creation
  762.   code to get correct colors when using a nondefault
  763.   visual.
  764. */
  765.  
  766. unsigned long
  767. MamaWhite(w)
  768.      MamaWidget w;
  769. { return w->mama.white;
  770. }
  771.  
  772. unsigned long
  773. MamaBlack(w)
  774.      MamaWidget w;
  775. { return w->mama.black;
  776. }
  777.  
  778. /* Print some performance statistics about the slaves */
  779.  
  780. void SlaveStatistics(w)
  781.      MamaWidget w;
  782. { wf_print_stats(w->mama.workforce, stdout);
  783. }
  784.